-
-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Don’t directly import numpy and add gen_types
decorator
#966
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #966 +/- ##
==========================================
+ Coverage 87.14% 87.24% +0.09%
==========================================
Files 9 9
Lines 4926 4948 +22
==========================================
+ Hits 4293 4317 +24
+ Misses 633 631 -2 ☔ View full report in Codecov by Sentry. |
param/_utils.py
Outdated
@@ -612,3 +612,15 @@ def async_executor(func): | |||
task.add_done_callback(_running_tasks.discard) | |||
else: | |||
event_loop.run_until_complete(func()) | |||
|
|||
|
|||
def anyinstance(obj, class_tuple_generator): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could an approach like this be used to avoid creating these functions? https://peps.python.org/pep-3119/#overloading-isinstance-and-issubclass
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, though I haven't read the PEP in detail.
However, it seems pretty advanced to use for a simple conversion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems it'd be something like:
import sys
class GeneratorIsMeta(type):
def __instancecheck__(cls, inst):
return isinstance(inst, tuple(cls.gen_types()))
def __subclasscheck__(cls, sub):
return issubclass(sub, tuple(cls.gen_types()))
class DtTypes(metaclass=GeneratorIsMeta):
@classmethod
def gen_types(cls):
yield dt.datetime
yield dt.date
if "numpy" in sys.modules:
import numpy as np
yield np.datetime64
class IntTypes(metaclass=GeneratorIsMeta):
@classmethod
def gen_types(cls):
yield int
if "numpy" in sys.modules:
import numpy as np
yield np.integer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you.
I still thinks it is pretty advanced (even though you don't need it to be iterable in your example).
You could likely move the advanced logic into a decorator, but then you would need to import that into our other libraries. My main point with accepting iterator is not so much for param itself but for HoloViews.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main point with accepting iterator is not so much for param itself but for HoloViews.
Oh yeah I agree users shouldn't have to pass this custom class, a generator seems appropriate. Instead I was wondering if there couldn't be a way to use the metaclass approach internally to avoid the special anyisinstance
and anyissubclass
functions, they seem to be easy to forget in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have switched to a metaclass approach with a decorator for easy access.
gen_types
decorator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just had one comment.
The changes made in this PR are not to directly import non-essential imports (numpy in param) but to only check for the case when the user has already imported them.
This comes down to two things:
For param, this is to "hide" numpy imports in functions or generators. This is strictly not necessary, but people check import time with
python -X importtime -c 'import param'
, and because we do an actual import of numpy, we are heavily penalized by it. The random modules (numpy and stdlib) also seem unnecessary to import, only to use the import for not outputting anything withpprint
.The second part involves using a new decorator, which overloads
isinstance
andissubclass
and still makes it function like a generator with and without calling it. This approach can be used in our other libraries, e.g., HoloViews. Here, we currently import pandas to set up different class selectors, which heavily penalizes the import time. We currently require pandas, but that may not always be the case.